﻿using Microsoft.Extensions.DependencyInjection;

using zijian666.DI.Abstractions;

namespace zijian666.DI.Defaults;

/// <summary>
/// 装配程序上下文
/// </summary>
public class DefaultAutowiredContext : List<object>, IAutowiredContext, IDisposable, IServiceProvider
{
    /// <summary>
    /// 服务提供程序
    /// </summary>
    public IServiceProvider Services { get; }
    /// <summary>
    /// 自动装配配置
    /// </summary>
    private readonly AutowiredConfig _config;

    /// <summary>
    /// 构造函数
    /// </summary>
    /// <param name="serviceProvider">服务提供程序</param>
    public DefaultAutowiredContext(IServiceProvider serviceProvider)
    {
        Services = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider));
        _config = serviceProvider.GetService<AutowiredConfig>() ?? new AutowiredConfig();
    }

    /// <summary>
    /// 从上下文缓存或服务提供程序中获取服务
    /// </summary>
    /// <param name="serviceType"></param>
    /// <returns></returns>
    public object? GetService(Type serviceType)
    {
        ThrowIfDisposed();
        if (serviceType is null)
        {
            return null;
        }
        if (serviceType == typeof(IAutowiredContext))
        {
            return this;
        }
        if (serviceType == typeof(IServiceProvider))
        {
            return Services;
        }
        if (serviceType == typeof(AutowiredConfig))
        {
            return _config;
        }
        var result = Services.GetService(serviceType);

        return result;
    }

    /// <summary>
    /// 自动装配
    /// </summary>
    /// <param name="instance">需要装配的服务实例</param>
    void IAutowiredContext.Add(object instance)
    {
        ThrowIfDisposed();
        ArgumentNullException.ThrowIfNull(instance);

        if (!Contains(instance))
        {
            // 将当前服务实体添加到上下文, 避免重复执行
            Add(instance);
        }
    }

    private void ThrowIfDisposed()
    {
        if (Disposed)
        {
            throw new ObjectDisposedException(nameof(DefaultAutowiredContext));
        }
    }

    /// <inheritdoc />
    public bool Disposed { get; private set; }

    /// <summary>
    /// 释放对象
    /// </summary>
    /// <param name="disposing">是否释放托管对象</param>
    protected virtual void Dispose(bool disposing)
    {
        if (!Disposed)
        {
            try
            {
                if (disposing)
                {
                    Clear();
                }
                // 释放未托管的资源(未托管的对象)并重写终结器
                // 将大型字段设置为 null
            }
            finally
            {
                Disposed = true;
            }
        }
    }

    /// <inheritdoc />
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
}